#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>

#define NULL_PTR ((void *)0)
#ifndef TRUE
#define TRUE (1u)
#endif
#ifndef FALSE
#define FALSE (0u)
#endif

typedef unsigned char uint8;
typedef unsigned uint32;
typedef unsigned char boolean;

#define QUEUE_SUCCESS (0)
#define QUEUE_ERROR_FULL (1)
#define QUEUE_ERROR_EMPTY (2)
#define QUEUE_ERROR_MEMORY (3)
#define QUEUE_ERROR_SIZE (4)

#define MAX_MESSAGES (4)
#define MESSAGE_LENGTH (8)

#define ENABLE_LOGGING (1) // 定义宏以启用日志记录
#define ENABLE_MALLOC (0)  // 使能动态内存分配
#define ENABLE_MAIN (1)    // 使能main函数样例

// 日志级别枚举
typedef enum
{
  LOG_LEVEL_DEBUG,
  LOG_LEVEL_INFO,
  LOG_LEVEL_WARN,
  LOG_LEVEL_ERROR
} LogLevel;

typedef struct
{
  uint8 data[MAX_MESSAGES][MESSAGE_LENGTH]; // 固定长度的消息队列
  uint32 current_memory;                    // 队列当前使用的内存大小
  uint32 front;                             // 队列头部
  uint32 rear;                              // 队列尾部
  uint32 size;                              // 队列当前大小
  boolean log_enabled;                      // 是否启用日志
  LogLevel log_level;                       // 当前日志级别
  uint32 log_error;                         // 日志错误状态
} Queue;

#if ENABLE_LOGGING
#define LOG(queue, level, format, ...) logMessage(queue, level, format, ##__VA_ARGS__)

// 获取当前时间字符串
uint8 *currentTime()
{
  time_t now = time(NULL_PTR);
  uint8 *time_str = ctime(&now);
  time_str[strlen(time_str) - 1] = '\0'; // 去掉换行符
  return time_str;
}

// 记录日志并打印到控制台
void logMessage(Queue *queue, LogLevel level, const uint8 *format, ...)
{
  if (queue->log_enabled && level >= queue->log_level)
  {
    va_list args;
    va_start(args, format);
    const uint8 *level_str;
    switch (level)
    {
    case LOG_LEVEL_DEBUG:
      level_str = "DEBUG";
      break;
    case LOG_LEVEL_INFO:
      level_str = "INFO";
      break;
    case LOG_LEVEL_WARN:
      level_str = "WARN";
      break;
    case LOG_LEVEL_ERROR:
      level_str = "ERROR";
      break;
    default:
      level_str = "UNKNOWN";
      break;
    }

    // 生成日志消息
    uint8 log_buffer[256];
    vsnprintf(log_buffer, sizeof(log_buffer), format, args);
    va_end(args);

    // 输出到控制台
    printf("[%s] [%s] %s\n", currentTime(), level_str, log_buffer);
  }
}
#else
#define LOG(queue, level, format, ...)
#endif

uint8 QueueInit(boolean log_enabled, LogLevel log_level, Queue *queue)
{
  if (!queue)
  {
    return QUEUE_ERROR_MEMORY;
  }
  queue->current_memory = 0;
  queue->front = 0;
  queue->rear = 0;
  queue->size = 0;
  queue->log_enabled = log_enabled;
  queue->log_level = log_level;
  queue->log_error = QUEUE_SUCCESS;
  return QUEUE_SUCCESS;
}

void destroyQueue(Queue *queue)
{
#if ENABLE_MALLOC
  free(queue);
#else
  memset(queue, 0x00, sizeof(Queue));
#endif
  LOG(queue, LOG_LEVEL_INFO, "Queue destroyed");
}

uint32 putQueue(Queue *queue, const uint8 *message, uint32 message_length)
{
  if (message_length > MESSAGE_LENGTH)
  {
    LOG(queue, LOG_LEVEL_ERROR, "Message length exceeds the limit");
    return QUEUE_ERROR_SIZE;
  }

  if (queue->size >= MAX_MESSAGES)
  {
    LOG(queue, LOG_LEVEL_WARN, "Queue is full, cannot putQueue message.");
    return QUEUE_ERROR_FULL;
  }

  memcpy(queue->data[queue->rear], message, message_length);
  queue->rear = (queue->rear + 1) % MAX_MESSAGES;
  queue->size++;
  queue->current_memory += MESSAGE_LENGTH;

  LOG(queue, LOG_LEVEL_INFO, "putQueue message of size %u.", message_length);
  return QUEUE_SUCCESS;
}

uint32 getQueue(Queue *queue, uint8 *message, uint32 message_length)
{
  if (queue->size == 0)
  {
    LOG(queue, LOG_LEVEL_WARN, "Queue is empty, cannot getQueue message.");
    return QUEUE_ERROR_EMPTY;
  }

  if (message_length < MESSAGE_LENGTH)
  {
    LOG(queue, LOG_LEVEL_ERROR, "Message length is too small to getQueue message.");
    return QUEUE_ERROR_SIZE;
  }

  memcpy(message, queue->data[queue->front], MESSAGE_LENGTH);
  for (uint32 i = 0; i < queue->size - 1; i++)
  {
    memcpy(queue->data[(queue->front + i) % MAX_MESSAGES], queue->data[(queue->front + i + 1) % MAX_MESSAGES], MESSAGE_LENGTH);
  }
  queue->rear = (queue->rear - 1 + MAX_MESSAGES) % MAX_MESSAGES;
  queue->size--;
  queue->current_memory -= MESSAGE_LENGTH;

  LOG(queue, LOG_LEVEL_INFO, "getQueue message of size %u.", MESSAGE_LENGTH);
  return QUEUE_SUCCESS;
}

void printQueue(Queue *queue)
{
#if ENABLE_LOGGING
  printf("Queue (size: %u, current_memory: %u):\n", queue->size, queue->current_memory);
  for (uint32 i = 0; i < queue->size; i++)
  {
    uint32 index = (queue->front + i) % MAX_MESSAGES;
    printf("  Message %u: ", i + 1);
    for (uint32 j = 0; j < MESSAGE_LENGTH; j++)
    {
      printf("%02X ", queue->data[index][j]);
    }
    printf("\n");
  }
#endif
}

#if ENABLE_MAIN
uint32 main()
{
  // 创建多个队列
#if ENABLE_MALLOC
  Queue *queue1 = (Queue *)malloc(sizeof(Queue));
  Queue *queue2 = (Queue *)malloc(sizeof(Queue));
#else
  Queue queue_instance1;
  Queue *queue1 = &queue_instance1;
  Queue queue_instance2;
  Queue *queue2 = &queue_instance2;
#endif

  // 初始化队列
  uint8 queue1_ret = QueueInit(TRUE, LOG_LEVEL_DEBUG, queue1);
  uint8 queue2_ret = QueueInit(TRUE, LOG_LEVEL_DEBUG, queue2);

  if (queue1_ret || queue2_ret)
  {
    printf("Failed to create queues\n");
    return QUEUE_ERROR_MEMORY;
  }

  // 用于queue1的消息
  const uint8 messages1_1[MESSAGE_LENGTH] = {0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
  const uint8 messages1_2[MESSAGE_LENGTH] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
  const uint8 messages1_3[MESSAGE_LENGTH] = {0x01, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  const uint8 messages1_4[MESSAGE_LENGTH] = {0x01, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};

  // 用于queue2的消息
  const uint8 messages2_1[MESSAGE_LENGTH] = {0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
  const uint8 messages2_2[MESSAGE_LENGTH] = {0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
  const uint8 messages2_3[MESSAGE_LENGTH] = {0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  const uint8 messages2_4[MESSAGE_LENGTH] = {0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};

  // 向queue1中添加消息
  if (putQueue(queue1, messages1_1, sizeof(messages1_1)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages1_1 in queue1\n");
  }
  if (putQueue(queue1, messages1_2, sizeof(messages1_2)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages1_2 in queue1\n");
  }
  if (putQueue(queue1, messages1_3, sizeof(messages1_3)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages1_3 in queue1\n");
  }
  if (putQueue(queue1, messages1_4, sizeof(messages1_4)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages1_4 in queue1\n");
  }

  // 向queue2中添加消息
  if (putQueue(queue2, messages2_1, sizeof(messages2_1)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages2_1 in queue2\n");
  }
  if (putQueue(queue2, messages2_2, sizeof(messages2_2)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages2_2 in queue2\n");
  }
  if (putQueue(queue2, messages2_3, sizeof(messages2_3)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages2_3 in queue2\n");
  }
  if (putQueue(queue2, messages2_4, sizeof(messages2_4)) != QUEUE_SUCCESS)
  {
    printf("Failed to putQueue messages2_4 in queue2\n");
  }

  // 打印两个队列的内容
  printf("Queue 1:\n");
  printQueue(queue1);

  printf("Queue 2:\n");
  printQueue(queue2);

  // 读取两个队列，并打印剩余内容
  uint8 buffer[MESSAGE_LENGTH];
  for (uint32 i = 0; i < 4; i++)
  {
    if (getQueue(queue1, buffer, sizeof(buffer)) == QUEUE_SUCCESS)
    {
      printf("getQueued message (queue1): ");
      for (uint32 j = 0; j < MESSAGE_LENGTH; j++)
      {
        printf("%02X ", buffer[j]);
      }
      printf("\n");
    }
    else
    {
      printf("Failed to getQueue\n");
    }
  }
  printQueue(queue1);

  for (uint32 i = 0; i < 4; i++)
  {
    if (getQueue(queue2, buffer, sizeof(buffer)) == QUEUE_SUCCESS)
    {
      printf("getQueued message (queue2): ");
      for (uint32 j = 0; j < MESSAGE_LENGTH; j++)
      {
        printf("%02X ", buffer[j]);
      }
      printf("\n");
    }
    else
    {
      printf("Failed to getQueue\n");
    }
  }
  printQueue(queue2);

  // 销毁队列
  destroyQueue(queue1);
  destroyQueue(queue2);

  return 0;
}
#endif
